package ge

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"strconv"

	"github.com/gin-gonic/gin"
)

// PageInfo 分页数据
type PageInfo struct {
	PageNo     int `json:"pageNo,omitempty"`
	PageSize   int `json:"pageSize,omitempty"`
	TotalCount int `json:"totalCount,omitempty"`
}

// Response 响应体
type Response struct {
	Status string `json:"status"` // success 或 failure
	Msg    string `json:"msg"`
	// 查询的结果集, put/post 行数
	Data any `json:"data"`
	// GetObjects 函数返回 PageInfo
	Data2 any `json:"data2"`
}

type Handler func(ctx *gin.Context) (data any, data2 any, errRtn error)

// CreateHandler handler 工厂
//
// 用法: r.GET("/users", CreateHandler(HandlerForUserList))
//
//	@param Handler handler 业务处理函数
//	@return gin.HandlerFunc handler 函数
func CreateHandler(h Handler) gin.HandlerFunc {
	return func(ctx *gin.Context) {
		data, data2, err := h(ctx)
		if err != nil {
			ctx.JSON(http.StatusOK, Response{Status: "failure", Msg: err.Error(), Data: data, Data2: data2})
			return
		}
		// h 有写入 ctx 的操作(比如文件下载),不再用 Json 否则会报错: wrote more than the declared Content-Length
		if i, _ := strconv.Atoi(ctx.Writer.Header().Get("Content-Length")); i > 0 {
			return
		}
		ctx.JSON(http.StatusOK, Response{Status: "success", Msg: "OK", Data: data, Data2: data2})
	}
}

// GetPostParams 取gin的post参数(json)
//
//	@param ctx 示例:[]{{"TmplID": "01001", "DepartID": "华北5"}}
//	@return data
func GetPostParams(ctx *gin.Context) (data []map[string]any) {
	var mp any
	if err := ctx.ShouldBindJSON(&mp); err != nil {
		fmt.Println(err)
		return
	}
	// 取查询过滤参数
	switch v := mp.(type) {
	case []any:
		for _, m := range v {
			data = append(data, m.(map[string]any))
		}
	case []map[string]any:
		data = v
	case map[string]any:
		data = []map[string]any{v}
	}
	return
}

// GetPutParams 取gin的put参数(json)
//
//	@param ctx 示例:{"where": {"Grade": 5, "Age": {">=", 3}}, "set": {"Age": 18}}
//	@return where 查询参数
//	@return set 设置参数
func GetPutParams(ctx *gin.Context) (where []map[string]any, set map[string]any) {
	body, _ := io.ReadAll(ctx.Request.Body)
	var mp map[string]any
	json.Unmarshal(body, &mp)
	// 取查询过滤参数
	if tmp, ok := mp["where"]; ok {
		// 支持条件数组
		if reflect.TypeOf(tmp).Kind() == reflect.Slice {
			where = make([]map[string]any, 0)
			for _, v := range tmp.([]interface{}) {
				where = append(where, v.(map[string]any))
			}
		} else {
			where = []map[string]any{tmp.(map[string]any)}
		}
	}
	if tmp, ok := mp["set"]; ok {
		set = tmp.(map[string]any)
	}
	return
}

// GetQryParams 取gin的请求参数(query, web不支持body)
//
//	@param ctx 示例: ?pageInfo={"pageNo":1,"pageSize":10}&qry={"TmplID":"01001","DepartID":"华北5"}&append=active='1'
//	@return p *PageInfo 分页
//	@return where 查询参数
//	@return sqlAppend 追加(order group....)
func GetQryParams(ctx *gin.Context) (p *PageInfo, where map[string]any, sqlAppend string) {
	var qry = struct {
		Where    map[string]any `form:"qry"`
		PageInfo *PageInfo      `form:"pageInfo"`
		Append   string         `form:"append"`
	}{}
	if err := ctx.ShouldBindQuery(&qry); err == nil { // query 方式
		p = qry.PageInfo
		where = qry.Where
		sqlAppend = qry.Append
	}
	return
}

// PostParams 取gin的post参数(json)
//
//	@param ctx 示例:{"TmplID": "01001", "DepartID": "华北5"}
//	@return data
func PostParams(ctx *gin.Context) (data map[string]any, err error) {
	err = ctx.ShouldBindJSON(&data)
	return
}

// PutParams 取gin的put参数(json)
//
//	@param ctx 示例:{"where": {"Grade": 5, "Age": {">=", 3}}, "set": {"Age": 18}}
//	@return where 查询参数(以 struct 更新时, 内容为空)
//	@return set 设置参数(以 struct 更新时, 内容struct)
func PutParams(ctx *gin.Context) (where map[string]any, set map[string]any, err error) {
	var mp map[string]any
	if err = ctx.ShouldBindJSON(&mp); err != nil {
		return
	}
	// 取查询过滤参数
	if tmp, ok := mp["where"]; ok {
		where = tmp.(map[string]any)
	}
	if tmp, ok := mp["set"]; ok {
		set = tmp.(map[string]any)
	} else {
		set = mp // 只发送 struct 的情况(用primaryKey处理)
	}
	return
}

// QryParams
//
//	@param ctx
//	@return where
//	@return pageNo
//	@return pageSize
//	@return sqlAppend
//	@return err
func QryParams(ctx *gin.Context) (where map[string]any, pageNo int, pageSize int, sqlAppend string, err error) {
	// 获取URL查询参数
	values := ctx.Request.URL.Query()
	if tmp, ok := values["pageNo"]; ok {
		// 解析pageNo
		pageNo, _ = strconv.Atoi(tmp[0])
		delete(values, "pageNo")
		pageSize = 10 // 默认值
	}
	if tmp, ok := values["pageSize"]; ok {
		// 解析pageSize
		pageSize, _ = strconv.Atoi(tmp[0])
		delete(values, "pageSize")
	}
	if tmp, ok := values["sqlAppend"]; ok {
		// 解析sqlAppend
		sqlAppend = tmp[0]
		delete(values, "sqlAppend")
	}
	if len(values) == 0 {
		return
	}
	where = make(map[string]any)
	// 解析其他查询参数
	for k, v := range values {
		if tmp, err := strconv.Atoi(v[0]); err == nil {
			// 解析为整数
			where[k] = tmp
		} else if tmp, err := strconv.ParseFloat(v[0], 64); err == nil {
			// 解析为浮点数
			where[k] = tmp
		} else if tmp, err := strconv.ParseBool(v[0]); err == nil {
			// 解析为布尔值
			where[k] = tmp
		} else {
			// 解析为字符串
			if len(v) == 1 {
				where[k] = v[0]
			} else {
				where[k] = v
			}
		}
	}
	return
}
